/*
 * @Author: 晟松
 * @Date: 2021-12-10 22:31:02
 * @LastEditors: 晟松
 * @LastEditTime: 2022-03-09 17:16:25
 * @FilePath: \mini-vue3d:\Code\node\koa2\volunteer-service\src\main\service\GroupVolService .js
 * @Description: 志愿服务的一些操作
 */

import sequelize from "@main/db";
import { isNull, isBlank } from "@main/util/ValidateUtil";
import { ParamError, LoginError, NotFoundError } from "@main/common/CommonError";
import { encryptPassword, checkPassword } from "@main/util/PasswordUtil";
import config from "@main/config";
import blacklist from "blacklist";
import whiteListed from "whitelisted";
import jwt from "jsonwebtoken";
import enums from "@main/config/enums";
import { toEnumNum, toEnumStr } from "@main/util/EnumsUtil";
import { type } from "koa/lib/response";
import dayjs from "dayjs";
import { where, Op } from "sequelize/dist";
import { nowTime } from "@main/util/TimeUtils";
import SchoolService from "./SchoolService";
import UserService from "./UserService";
import Web3Service from "./Web3Service";

// 获取所有定义的model
const models = sequelize.models;

class GroupVolService {
    /**
     * @description: 居民添加志愿服务
     * @param {*} params
     * @return {*}
     */
    static async add(params) {
        // id为发起的居委会id，isPublic表示是否是公开的,recipientId为单独发给某一个学校或辅导员
        let { id: initiatorId, isPublic, recipientId } = params;
        let groupVolInfo = blacklist(params, "id");

        // 初始状态表示为等待领取的状态
        groupVolInfo.state = enums.state["alreadyClaimed"];
        // 默认是公开的
        if (isBlank(groupVolInfo.isPublic)) groupVolInfo.isPublic = true;

        console.log("groupVolInfo: ", groupVolInfo);
        // 将一些别的字段混合进groupVolInfo中

        Object.assign(groupVolInfo, {
            initiatorId,
        });
        // 单独发送给其他人
        if (!isPublic) {
            Object.assign(groupVolInfo, {
                recipientId,
                state: enums.state["alreadyClaimed"],
            });
        }
        let res = await models["groupVol"].create(groupVolInfo);

        await Web3Service.updateOne("groupVol", res.id);
        return res;
    }

    static async delete(params) {
        let { id: initiatorId, groupVolId } = params;
        await models["student_groupVol"].destroy({
            where: {
                groupVolId: groupVolId,
            },
        });
        return await models["groupVol"].destroy({
            where: {
                id: groupVolId,
                initiatorId: initiatorId,
            },
        });
    }
    /**
     * @description: 居委会获得自己所有的大型志愿服务记录
     * @param {*} params
     * @return {*}
     */
    static async getMineGroupVol(params) {
        // id为居委会id
        let { id, limit, offset } = params;
        if (!isNull(limit)) limit -= 0;
        if (!isNull(offset)) offset -= 0;

        let allStudentGroupVol = await models["groupVol"].findAll({
            where: {
                initiatorId: id,
            },
            limit,
            offset,
            include: models.student, //直接通过include，获取这个groupVol所相关联的所有学生信息
        });

        console.log("allStudentGroupVol: ", allStudentGroupVol[0].students);
        for (let i = 0; i < allStudentGroupVol.length; i++) {
            // 注意这里是领取的学生们
            allStudentGroupVol[i].dataValues.recipientStudents = [];
            // 注意相关联的学生是一个数组
            for (let j = 0; j < allStudentGroupVol[i].students.length; j++) {
                let res = await UserService.findUserInfo({
                    id: allStudentGroupVol[i].students[j].id,
                    identity: "student",
                });
                allStudentGroupVol[i].dataValues.recipientStudents.push(res);
            }
            // 将居委会的信息加上去
            allStudentGroupVol[i].dataValues.initiatorUser = await UserService.findUserInfo({
                id: allStudentGroupVol[i].initiatorId,
                identity: "community",
            });

            // 这个就是如果有领取的学校的话，就需要这个获得一些信息了
            if (!isBlank(allStudentGroupVol[i].dataValues.recipientId)) {
                allStudentGroupVol[i].dataValues.recipientUser = await UserService.findUserInfo({
                    id: allStudentGroupVol[i].recipientId,
                    identity: "school",
                });
            }
        }
        return allStudentGroupVol;
    }
    /**
     * @description: 获得一个大型志愿服务相关的学生
     * @param {*} params
     * @return {*}
     */
    static async getRelativeStudent(params) {
        let { groupVolId } = params;
        let allRelative = await models["student_groupVol"].findAll({
            where: {
                groupVolId,
            },
        });
        let allStudent = [];
        for (let i = 0; i < allRelative.length; i++) {
            let studentId = allRelative[i].studentId;
            allStudent.push(
                await models["student"].findOne({
                    where: {
                        id: studentId,
                    },
                    include: models["login"],
                })
            );
        }
        return allStudent;
    }
    /**
     * @description: 学校获得自己的大型志愿服务
     * @param {*} params
     * @return {*}
     */
    static async schoolGetMineGroupVol(params) {
        //  id为校级管理员或院级辅导员的id
        let { id, limit, offset } = params;
        if (!isNull(limit)) limit -= 0;
        if (!isNull(offset)) offset -= 0;

        return await models["groupVol"].findAll({
            where: {
                recipientId: id,
            },
            limit,
            offset,
        });
    }
    /**
     * @description: 更新一个大型志愿服务本身的信息
     * @param {*} params
     * @return {*}
     */
    static async update(params) {
        let { groupVolId: id } = params;
        let updateInfo = blacklist(params, "groupVolId");
        let res = await models["groupVol"].update(updateInfo, {
            where: {
                id,
            },
        });

        await Web3Service.updateOne("groupVol", id);
        return res;
    }
    /**
     * @description: 获得一个大型志愿服务本身的信息
     * @param {*} params
     * @return {*}
     */
    static async getGroupVolInfo(params) {
        let { groupVolId: id } = params;
        let groupVolInfo = await models["groupVol"].findOne({
            where: {
                id,
            },
        });
        groupVolInfo.dataValues.initiatorUser = await models["community"].findOne({
            where: {
                id: groupVolInfo.dataValues.initiatorId,
            },
            include: models["login"],
        });
        return groupVolInfo;
    }
    /**
     * @description: 获得所有公开且未被领取的大型志愿服务，主要是针对学校而言的，单个学生而言基本用不上
     * @param {*} params
     * @return {*}
     */
    static async getPublicGroupVol(params) {
        let { limit, offset } = params;
        if (!isNull(limit)) limit -= 0;
        if (!isNull(offset)) offset -= 0;

        return await models["groupVol"].findAll({
            where: {
                isPublic: true,
                recipientId: null,
            },
            limit,
            offset,
        });
    }
    /**
     * @description: 学校领取大型志愿服务，校级可以领取，院级也可以领取
     * @param {*} params
     * @return {*}
     */
    static async receiveGroupVol(params) {
        // id为领取者的id，即学校管理员/院级辅导员的id
        let { id, groupVolId } = params;
        // 注意需要将ispublic改为false，让其他人看不见
        let res = await models["groupVol"].update(
            {
                recipientId: id,
                state: enums.state["alreadyClaimed"],
                isPublic: false,
                recipientTime: nowTime(),
            },
            {
                where: {
                    id: groupVolId,
                },
            }
        );
        await Web3Service.updateOne("groupVol", groupVolId);
        return res;
    }
    /**
     * @description: 学生自主或被动领取一个大型志愿服务
     * @param {*} params
     * @return {*}
     */
    static async studentReceiveGroupVol(params) {
        // id为领取者的id，即学生id
        let { id, groupVolId } = params;
        let groupVol = await models.groupVol.findOne({
            where: {
                id: groupVolId,
            },
        });
        // 人已经够了
        if (groupVol.realPeopleNum >= groupVol.peopleNum) {
            throw new Error("人数已够");
        }

        // 人数够了，更新状态，直接就更新到等待反馈这一步
        if (groupVol.realPeopleNum + 1 == groupVol.peopleNum) {
            await models.groupVol.update(
                {
                    state: enums.state["pendingFeedback"],
                },
                {
                    where: {
                        id: groupVolId,
                    },
                }
            );
        }
        // 更新实际人数
        await models.groupVol.update(
            {
                realPeopleNum: groupVol.realPeopleNum + 1,
            },
            {
                where: {
                    id: groupVolId,
                },
            }
        );

        await Web3Service.updateOne("groupVol", groupVolId);

        let res = await models["student_groupVol"].create({
            studentId: id,
            groupVolId,
        });

        // 将这个关联表中的这个数据也存起来
        await Web3Service.updateStudentGroupVol(id, groupVolId);
        return res;
    }
    /**
     * @description: 学生获取自己领取的大型志愿服务
     * @param {*} params
     * @return {*}
     */
    static async studentGetMineGroupVol(params) {
        // id为学生的id
        let { id } = params;
        let allReceive = await models["student"].findOne({
            where: {
                id,
            },
            include: models.groupVol,
        });
        let allGroupVol = allReceive.groupVols;
        return allGroupVol;
    }

    /**
     * @description: 获得一个大型志愿服务的所有关联的学生，即领取了这个大型志愿服务的学生
     * @param {*} params
     * @return {*}
     */
    static async getGroupVolRelativeStudent(params) {
        // id为学生的id
        let { groupVolId } = params;
        let relativeStudent = await models["student_groupVol"].findAll({
            where: {
                groupVolId,
            },
        });
        let allStudent = [];
        for (let i = 0; i < relativeStudent.length; i++) {
            let res = await UserService.findUserInfo({
                id: relativeStudent[i].studentId,
                identity: "student",
            });
            allStudent.push(res);
        }
        return allStudent;
    }
    /**
     * @description: 校级管理员或院级辅导员获得自己的学生的大型志愿服务
     * @param {*} params
     * @param {*} user
     * @return {*}
     */
    static async schoolGetStudentGroupVol(params, user) {
        // 获取学校的id，通过查询对应身份，判断是校级管理员还是辅导员，然后得到所有学生的信息还是自己院里的学生的信息
        let { schoolId } = params;
        let school = await models.school.findOne({
            where: {
                id: schoolId,
            },
        });
        let allStudentGroupVol = [];
        if (school.managementLevel == enums.managementLevel.school) {
            let allStudent = await SchoolService.getAllStudent({ id: schoolId });
            for (let i = 0; i < allStudent.length; i++) {
                let res = await GroupVolService.studentGetMineGroupVol({ id: allStudent[i].id });
                allStudentGroupVol.push(...res);
            }
        } else {
            // 只是一个辅导员
            let allStudent = await SchoolService.getAllCollegeStudent({ id: schoolId });
            for (let i = 0; i < allStudent.length; i++) {
                let res = await GroupVolService.studentGetMineGroupVol({ id: allStudent[i].id });
                allStudentGroupVol.push(...res);
            }
        }
        console.log("allStudentGroupVol: ", allStudentGroupVol[0]);
        // 将领取者和发起者的信息也加上去
        for (let i = 0; i < allStudentGroupVol.length; i++) {
            // 注意这里的recipientUser指的是领取任务的学生，而不是领取的学校
            allStudentGroupVol[i].dataValues.recipientUser = await UserService.findUserInfo({
                // 注意一下这里的id是这个，而不是领取者的id,即学校辅导员这些的id
                id: allStudentGroupVol[i].student_groupVol.studentId,
                identity: "student",
            });
            // 将居委会的信息加上去
            allStudentGroupVol[i].dataValues.initiatorUser = await UserService.findUserInfo({
                id: allStudentGroupVol[i].initiatorId,
                identity: "community",
            });
        }
        return allStudentGroupVol;
    }

    /**
     * @description: 学生获取自己可领取的大型志愿服务列表
     * @param {*} params
     * @return {*}
     */
    /* static async studentGetGroupVolList(studentInfo) {
        console.log("studentInfo: ", studentInfo);
        // 先获取公开的,且状态还在等待领取的状态
        let groupVolList = await models["groupVol"].findAll({
            where: {
                state: enums.state["approved"],
                isPublic: true,
            },
        });
        // 挂载发起者的信息
        for (let i = 0; i < groupVolList.length; i++) {
            groupVolList[i].dataValues.initiatorUser = await models["community"].findOne({
                where: {
                    id: groupVolList[i].dataValues.initiatorId,
                },
                include: models["login"],
            });
        }
        return groupVolList;
    } */

    /**
     * @description: 学生获取自己学校或学院领取的大型志愿服务或公开的大型志愿服务列表
     * @param {*} params
     * @return {*}
     */
    static async studentGetGroupVolList(params) {
        // id为学生的id,schoolId为自己辅导员的id
        let { id, schoolId } = params;
        let stu = await models.student.findOne({
            where: {
                id,
            },
            include: models.login,
        });

        // 即辅导员id
        if (!schoolId) {
            schoolId = stu.schoolId;
        }
        // 获得辅导员的信息
        let college = await models.school.findOne({
            where: {
                id: schoolId,
            },
        });

        /* 注意这里就变为了学校管理员的id了 */
        schoolId = college.schoolId;

        // 去groupVol里面查找已被此学校领取且还在找人的大型志愿服务
        let schoolReceiveGroupVol = await models.groupVol.findAll({
            where: {
                recipientId: schoolId,
                state: enums.state["alreadyClaimed"],
                time: {
                    [Op.gt]: nowTime(), // 要志愿服务的时间也要大于当前时间
                },
            },
        });

        // 查询所有公开的大型志愿服务
        let publicGroupVol = await models["groupVol"].findAll({
            where: {
                state: enums.state["alreadyClaimed"], // 注意这里的状态
                isPublic: true,
                time: {
                    [Op.gt]: nowTime(), // 要志愿服务的时间也要大于当前时间
                },
            },
        });
        // 添加公开的大型志愿服务的发起人信息
        for (let i = 0; i < publicGroupVol.length; i++) {
            publicGroupVol[i].dataValues.initiatorUser = await models["community"].findOne({
                where: {
                    id: publicGroupVol[i].dataValues.initiatorId,
                },
                include: models["login"],
            });
        }

        // 添加自己学校领取的大型志愿服务的发起者信息
        for (let i = 0; i < schoolReceiveGroupVol.length; i++) {
            schoolReceiveGroupVol[i].dataValues.initiatorUser = await models["community"].findOne({
                where: {
                    id: schoolReceiveGroupVol[i].dataValues.initiatorId,
                },
                include: models["login"],
            });
        }
        // 学校推荐和公开大型志愿服务
        return { schoolReceiveGroupVol, publicGroupVol };
    }

    /**
     * @description: 居民获取自己居委会发起的大型志愿服务
     * @param {*} params
     * @return {*}
     */
    static async residentGetGroupVolList(params, user) {
        // id为居民id
        let { id } = params;
        // 居委会id
        let { communityId } = user;

        // 查询所有公开的大型志愿服务
        let publicGroupVol = await models["groupVol"].findAll({
            where: {
                state: enums.state["alreadyClaimed"], // 注意这里的状态
                initiatorId: communityId, //自己居委会发起的
                time: {
                    [Op.gt]: nowTime(), // 要志愿服务的时间也要大于当前时间
                },
            },
        });
        return { publicGroupVol };
    }
    /**
     * @description: 志愿服务领取者发起反馈
     * @param {*} params
     * @return {*}
     */
    static async feedbackGroupVol(params) {
        let { groupVolId: id, feedback } = params;

        // 先找到对应的大型志愿服务
        let groupVol = await models.groupVol.findOne({
            where: {
                id,
            },
        });
        // 然后对反馈这一块进行特殊加载,简单的画成数组
        if (groupVol.feedback) feedback = groupVol.feedback + "|" + feedback;
        let updateInfo = {
            feedback,
            state: enums.state["toBeEvaluated"],
        };
        let res = await models["groupVol"].update(updateInfo, {
            where: {
                id,
            },
        });

        await Web3Service.updateOne("groupVol", id);
        return res;
    }
    /**
     * @description: 发起者评价整个志愿服务，包括分数等
     * @param {*} params
     * @return {*}
     */
    static async evaluateGroupVol(params) {
        let { groupVolId: id, evaluation, evaluationScore } = params;
        let updateInfo = {
            state: enums.state["completed"],
            evaluation,
            evaluationScore,
        };

        // 使用事务
        try {
            const result = await sequelize.transaction(async (t) => {
                await models["groupVol"].update(updateInfo, {
                    where: {
                        id,
                    },
                });

                await Web3Service.updateOne("groupVol", id);
                // 将时间积分发给领取了这个大型志愿服务的学生
                let { timeIntegral } = await models["groupVol"].findOne({
                    where: {
                        id,
                    },
                });

                let allRecipient = await models["student_groupVol"].findAll({
                    where: {
                        groupVolId: id,
                    },
                });
                for (let i = 0; i < allRecipient.length; i++) {
                    let student = await models["student"].findOne({
                        where: {
                            id: allRecipient[i].studentId,
                        },
                    });
                    console.log("student: ", student);
                    await models["student"].update(
                        {
                            timeIntegral: student.timeIntegral + timeIntegral,
                        },
                        {
                            where: {
                                id: student.id,
                            },
                        }
                    );

                    await Web3Service.updateOne("student", student.id);
                }
                return allRecipient;
            });

            return result;
            // 如果执行到此行,则表示事务已成功提交,`result`是事务返回的结果
            // `result` 就是从事务回调中返回的结果(在这种情况下为 `user`)
        } catch (error) {
            // 如果执行到此,则发生错误.
            // 该事务已由 Sequelize 自动回滚！
        }
    }
}

export default GroupVolService;
